﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Helpers;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Wechat.Util.ReturnMessage;
using Wechat.Util.StateCode;

namespace Wechat.API.Filter
{
    public class AntiXssSqlInjectAttribute : FilterAttribute, IActionFilter
    {
        /// <summary>
        /// 防XSS_SQL注入攻击正则规范
        /// </summary>
        private const string StrXssSqlRegEx = @"<[^>]+?style=[\w]+?:expression\(|\b(alert|confirm|prompt)\b|^\+/v(8|9)|<[^>]*?=[^>]*?&#[^>]*?>|\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|/\*.+?\*/|<\s*script\b|<\s*img\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";

        #region 利用线程进行请求的xss_sql攻击正则验证

        /// <summary>
        /// 利用线程进行请求的xss_sql攻击正则验证
        /// </summary>
        /// <param name="actionContext"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="continuation"></param>
        /// <returns></returns>
        public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
        {
            var actionParameters = actionContext.ActionDescriptor.GetParameters();
            Task<HttpResponseMessage> httpResponseMessage = null;

            foreach (var p in actionParameters)
            {
                if (p.ParameterType.Equals(typeof(string)))
                {
                    string parm = Convert.ToString(actionContext.ActionArguments[p.ParameterName]);
                    if (!string.IsNullOrWhiteSpace(parm))
                        httpResponseMessage = ErrorResultMsg(actionContext, p.ParameterName, parm);
                }
                else
                {
                    var parmObj = actionContext.ActionArguments[p.ParameterName];
                    foreach (var pi in parmObj.GetType().GetProperties())
                    {
                        if (pi.PropertyType.Equals(typeof(string)))
                        {
                            string parm = Convert.ToString(pi.GetValue(parmObj));
                            if (!string.IsNullOrWhiteSpace(parm))
                            {
                                httpResponseMessage = ErrorResultMsg(actionContext, pi.Name, parm);
                                if (httpResponseMessage != null)
                                    break;
                            }
                        }
                    }
                }

                if (httpResponseMessage != null)
                    break;
            }

            return httpResponseMessage ?? continuation();
        }

        #endregion

        #region 错误消息

        /// <summary>
        /// 错误消息
        /// </summary>
        /// <param name="actionContext"></param>
        /// <param name="parmName"></param>
        /// <param name="parmValue"></param>
        /// <returns></returns>
        private static Task<HttpResponseMessage> ErrorResultMsg(HttpActionContext actionContext, string parmName, string parmValue)
        {
            foreach (string regEx in StrXssSqlRegEx.Split('?'))
            {
                if (Regex.IsMatch(parmValue, regEx, RegexOptions.IgnoreCase))
                {
                    ResultMessage resultMsg = new ResultMessage();
                    resultMsg.Status = false;
                    resultMsg.Code = (int)EnumApiStateCode.XssSqlInject;
                    resultMsg.Message = string.Format("请求参数[{0}]高危！", parmName);

                    var response = actionContext.Response ?? new HttpResponseMessage();
                    response.StatusCode = HttpStatusCode.Forbidden;

                    response.Content =
                        new StringContent(
                            Json.Encode(new
                            {
                                status = resultMsg.Status,
                                code = resultMsg.Code,
                                message = resultMsg.Message
                            }), Encoding.UTF8, "application/json");

                    return Task.FromResult(response);
                }
            }
            return null;
        }

        #endregion

    }
}